fix(ci): harden against template injection and credential exposure#15
Merged
Conversation
38eae37 to
ef9aa3e
Compare
Move ${{ context }} expressions to env: variables to prevent shell
injection at the GitHub Actions template layer.
Also filter INPUT_* variables from wolfi-act.github.env before passing
it to `docker run --env-file`. INPUT_COMMAND is a multi-line script;
Docker's env file parser rejects values containing whitespace, causing
exit code 125. The INPUT_* vars are consumed by the action script before
the container runs and do not need to be forwarded into the container.
Refs: PSEC-923
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add persist-credentials: false to both checkout steps in ci.yml, since
no downstream git operations rely on the credential store. Add
permissions: {} at workflow level and explicit contents: read per-job
blocks for ci and ci-debug jobs.
Refs: PSEC-923
Switch zizmor CI workflow to pedantic persona to catch all template expansions in run: blocks. Add paths: triggers to zizmor.yaml to ensure changes to .github/zizmor.yml and .github/dependabot.yml are checked. Disable anonymous-definition, undocumented-permissions, and concurrency-limits in .github/zizmor.yml — these are pedantic-only rules with no direct security value that would generate CI noise without actionable remediation. Refs: PSEC-923
Quote ${PWD} in two docker run -v mount arguments to prevent word
splitting on paths with spaces.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ef9aa3e to
91a6dc1
Compare
Member
Author
|
The ci failing here is not cuased by this pr, but is because https://raw.githubusercontent.com/chainguard-images/images/main/images/maven/config/template.apko.yaml no longer exists (a raw apko config is no longer used for image config). This is intended to be addressed by #16 which switches to an example apko config from the apko repository. |
egibs
approved these changes
May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(ci): harden against template injection and credential exposure
Refs: PSEC-923
Repo: wolfi-dev/wolfi-act
Scan date: 2026-05-03
Patches: 4
Summary
This patch series addresses security findings from
zizmor --persona=auditoracrossthe workflows and composite action in
wolfi-dev/wolfi-act. The four patches areatomic by change type and apply cleanly in order.
Patch 0001 — fix(ci): resolve template injection findings; fix env file for container
File changed:
action.ymlSix
template-injectionfindings identified in the composite action's singlerun:block.All six involved
${{ inputs.* }}template expressions evaluated by GitHub Actions beforethe shell runs. The affected expressions were:
${{inputs.debug}}— passed as a single-quoted shell value${{inputs.command}}— used in an empty check and passed to bash for execution${{inputs.packages}}— used for package list iteration${{ inputs.apko-image }}— passed as a docker image argument${{ inputs.command }}(×2) — echoed and passed as the script tobash -cFix: Added an
env:block (beforerun:for readability) with four variables:INPUT_DEBUG,INPUT_COMMAND,INPUT_PACKAGES,INPUT_APKO_IMAGE. Updated all sixin-shell references to use
"${VAR}"double-quoted expansions. The single-quote shellcontext was intentional to protect against glob expansion, but the GitHub Actions template
is evaluated before the shell sees the script, so single-quoting does not prevent injection
of special characters from input values.
Also in this patch: Changed
env > wolfi-act.github.envto awhileloop overenv -0to safely filterINPUT_*variables and any vars with embedded newlines beforepassing the env file to any line-oriented consumer. Moving inputs to
env:variablescauses
INPUT_COMMAND(a multi-line shell script) to appear in the runner's environment.Plain
envoutputs multi-line values as raw newlines, so a simplegrep -v '^INPUT_'only removes the first line — continuation lines pass through and break consumers expecting
one
NAME=VALUEper line. Agrep -z -v $'\n'filter to drop multi-line records alsofails:
grep -vreturns exit code 1 when nothing is filtered out, which kills thepipeline under
set -o pipefail. Thewhileloop overenv -0(null-terminatedrecords) avoids both problems: each record is processed atomically regardless of embedded
newlines, and the loop always exits 0.
Note:
inputs.commandis by design user-supplied executable shell code (the entire purposeof wolfi-act is to run arbitrary commands in a Wolfi ephemeral container). Moving to an env
var prevents template injection at the Actions layer; the command still executes as bash.
See
manual-review.mdfor a documentation recommendation.Patch 0002 — fix(ci): add persist-credentials: false and scope workflow permissions
File changed:
.github/workflows/ci.ymlArtipacked (2 findings): Both
actions/checkoutsteps inci.yml(jobsciandci-debug) lackedpersist-credentials: false. Neither job performs any git writeoperations after checkout, and the action under test (
./) uses its own Docker-basedephemeral runner that does not use the git credential store.
persist-credentials: falseis correct.
Excessive permissions (3 findings):
ci.ymlhad no workflow-levelpermissions:block(defaulting to broad implicit permissions) and no per-job
permissions:blocks. Both jobsonly require
contents: read(for checkout). Fixed by:permissions: {}at workflow level (deny-all default)permissions: { contents: read }explicitly to bothciandci-debugjobsNo changes to
build.yml— its existingpermissions:blocks are correctly scoped(
contents: readat workflow level;packages: writeandid-token: writeat build-joblevel for GHCR push and cosign keyless signing respectively).
Patch 0003 — fix(ci): add pedantic persona and suppress noisy zizmor rules
Files changed:
.github/workflows/zizmor.yaml,.github/zizmor.ymlzizmor persona: Added
persona: pedanticto thezizmorcore/zizmor-actionstep inzizmor.yaml. This switches from the defaultregularpersona topedantic, catchingall
${{ }}template expansions inrun:blocks (not only attacker-controlled sources).Paths triggers: Added
paths:filters to bothpull_requestandpushtriggers inzizmor.yamlto includeaction.yml,.github/dependabot.yml, and.github/zizmor.yml.The
action.ymlentry is necessary because wolfi-act's composite action definition lives atthe repo root (not under
.github/), so changes to it would otherwise not trigger the check.Rule suppression in
.github/zizmor.yml: Added three disabled rules:anonymous-definition— pedantic-only, no security impact (cosmetic)undocumented-permissions— pedantic-only, pure documentation styleconcurrency-limits— low security value, generates 4 findings in this repo aloneThese suppressed the 4
concurrency-limits, 4anonymous-definition, and 1undocumented-permissionsfindings that are noise without actionable remediation.Patch 0004 — fix(ci): quote $PWD in docker run arguments (SC2086)
File changed:
action.ymlTwo occurrences of
-v ${PWD}:/work \in docker run commands were unquoted.Quoted to
-v "${PWD}":/work \to prevent word splitting on paths with spaces(SC2086). No logic change.
Findings not auto-fixed
1 × stale-action-refs —
build.yml:31wolfi-dev/wolfi-act@c7bc05c8af23bca710b267e0db3b39c939eb7b02 # mainis a self-referentialpin (the workflow references itself). zizmor flags this SHA as not corresponding to a Git
tag. Requires an online check to determine if a tag has since been created for this commit.
Documented in
manual-review.md.Finding counts
template-injectionartipackedexcessive-permissionsstale-action-refsconcurrency-limitsanonymous-definitionundocumented-permissionsRefs: PSEC-923